﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System.Diagnostics;
using Windows.Phone.Speech.Synthesis;
using System.Threading;
using System.Windows.Threading;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using Windows.Phone.Speech.Recognition;
using AllenHung.FeedReader.Resources;
using System.ComponentModel;
using Windows.Foundation;


namespace AllenHung.FeedReader
{
    public partial class ArticlePage : PhoneApplicationPage
    {
        private int tickCount = 0;
        private DispatcherTimer speechTimer;                        
        internal SpeechRecognizer recognizer;
        private bool recognizeInProgress = false;
        private int skipCounter = 0; 
        internal SpeechSynthesizer synthesizer;                             // The speech synthesizer (text-to-speech, TTS) object
        private static string[] ArticlePageVocabulary = new string[] {
            "yes", "no"
        };
        private Dictionary<string, Action> ActionMap = null;
        private static bool ExecutingCommand = false;
        private IAsyncAction task;


        public ArticlePage()
        {
            InitializeComponent();
            synthesizer = new SpeechSynthesizer(); recognizer = new SpeechRecognizer();
            recognizer.Grammars.AddGrammarFromList("ArticlePage", ArticlePageVocabulary);
            ActionMap = new Dictionary<string, Action>();
            ActionMap.Add(ArticlePageVocabulary[0], this.YesNext);
            ActionMap.Add(ArticlePageVocabulary[1], this.NoNext);
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            Debug.WriteLine("OnNavigatedTo ArticlePage");
            App.CurrentPage = 3;
            articleTitle.Text = App.articleTitle;
            articleText.Text = App.article;
            readArticle();
            if (!App.SpeechOn)
            {
                BitmapImage muteImage = new BitmapImage(new Uri("/Assets/mute.png", UriKind.Relative));
                SpeechButtonImage.Source = muteImage;
                SpeechStatusText.Background = (Brush)Application.Current.Resources["DisabledBrush"];
                SpeechStatusText.BorderBrush = (Brush)Application.Current.Resources["DisabledBrush"];
                SpeechStatusText.Content = "Disabled";
            }
            else
            {
                speechTimer = new System.Windows.Threading.DispatcherTimer();
                speechTimer.Tick += new EventHandler(speechTimer_Tick);
                speechTimer.Interval = new TimeSpan(500 * TimeSpan.TicksPerMillisecond);
                speechTimer.Start();
                BitmapImage muteImage = new BitmapImage(new Uri("/Assets/microphone.png", UriKind.Relative));
                SpeechButtonImage.Source = muteImage;
                SpeechStatusText.Background = (Brush)Application.Current.Resources["FeedBrush"];
                SpeechStatusText.BorderBrush = (Brush)Application.Current.Resources["FeedBrush"];
                SpeechStatusText.Content = "Listening ...";
            }
        }
        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            App.CurrentPage = 0;
            Debug.WriteLine("OnNavigatedFrom ArticlePage");
           

            //synthesizer.CancelAll();
            
            //task.Cancel();

            App.syndItems.Clear();
        }

        private async void readArticle()
        {
            if (App.SpeechOn)
            {
                await synthesizer.SpeakTextAsync(articleTitle.Text);

                await synthesizer.SpeakTextAsync(articleText.Text);
                
            }

            if (App.AutoplayNext && App.SpeechOn)
            {
                RssTextTrimmer textTrimmer = new RssTextTrimmer();
                for (int i = 0; i < App.syndItems.Count; i++)
                {
                    articleText.Text = App.syndItems.ElementAt(i).Summary.Text;
                    articleText.Text = textTrimmer.Convert(articleText.Text, null, null, null).ToString();
                    articleTitle.Text = App.syndItems.ElementAt(i).Title.Text;
                    if (App.CurrentPage != 3)
                        break;
                    await synthesizer.SpeakTextAsync("Next Article");

                    if (App.CurrentPage != 3)
                        break;
                    await synthesizer.SpeakTextAsync(articleTitle.Text);

                    if (App.CurrentPage != 3)
                        break;
                    await synthesizer.SpeakTextAsync(articleText.Text);

                    if (App.CurrentPage != 3)
                        break;
                }
            }
            else if(App.SpeechOn)
            {
                NavigationService.Navigate(new Uri("/ArticleListPage.xaml", UriKind.Relative));

            }
        }

        private async void speechTimer_Tick(object sender, EventArgs e)
        {
            tickCount = (tickCount + 1) % 10000;
            int curTick = tickCount;
            if (!recognizeInProgress)
            {
                Debug.WriteLine(curTick + " Start recognizing");
                skipCounter = 0;
                //recognizeInProgress = true;
                try
                {// Start recognition.
                    SpeechRecognitionResult recoResult = await recognizer.RecognizeAsync();
                    if (App.CurrentPage != 3)
                    {
                        Debug.WriteLine(curTick + " party over page navigated away");
                        return;
                    }
                    // Check to see if speech input was rejected and prompt the user.
                    if (recoResult.TextConfidence == SpeechRecognitionConfidence.Rejected)
                    {
                        Debug.WriteLine(curTick + " Rejected silence");
                    }

                    // Check to see if speech input was recognized with low confidence and prompt the user to speak again.
                    else if (recoResult.TextConfidence == SpeechRecognitionConfidence.Low ||
                        recoResult.TextConfidence == SpeechRecognitionConfidence.Medium)
                    {
                        if (ExecutingCommand)
                        {
                            Debug.WriteLine(curTick + " low confidence someone already take care of this");
                        }
                        else
                        {
                            Debug.WriteLine(curTick + " Sorry I didn't get that");
                            SetSpeechStatusText("Sorry I didn't get that");
                            await synthesizer.SpeakTextAsync("Sorry I didn't get that");
                        }
                    }

                    // Check to see if speech input was recognized and confirm the result.
                    else if (recoResult.TextConfidence == SpeechRecognitionConfidence.High)
                    {
                        if (ExecutingCommand)
                        {
                            Debug.WriteLine(curTick + " someone already take care of this");
                        }
                        else
                        {
                            Debug.WriteLine(curTick + " You say " + recoResult.Text);
                            SetSpeechStatusText("You say " + recoResult.Text);
                            if (ActionMap.ContainsKey(recoResult.Text))
                            {
                                ExecutingCommand = true;
                                Action act = ActionMap[recoResult.Text];
                                act();
                                BackgroundWorker backgroundWorker = new BackgroundWorker();
                                backgroundWorker.DoWork += new DoWorkEventHandler(ResetExecutingCommandStatus);
                                backgroundWorker.RunWorkerAsync();
                            }
                            else
                            {
                                await synthesizer.SpeakTextAsync(recoResult.Text + " is an unknown command. Say \"next\", \"previous\", or \"select\"");
                            }
                        }
                    }
                    recognizeInProgress = false;
                    Debug.WriteLine(curTick + " Recognizing done");
                }
                catch (Exception exc)
                {
                    Debug.WriteLine(curTick + " HRESULT: " + exc.HResult + " " + exc.StackTrace);
                    Debug.WriteLine(curTick + " HRESULT: " + exc.HResult + " " + exc.Message);
                }
            }
            else
            {
                if (++skipCounter == 10)
                {
                    Debug.WriteLine(curTick + " Stale recognizer");
                    recognizer = new SpeechRecognizer();
                    recognizer.Grammars.AddGrammarFromList("ArticlePage", ArticlePageVocabulary);
                    recognizeInProgress = false;
                }
                Debug.WriteLine(curTick + " Skip recognizing");
            }
        }

        private void SetSpeechStatusText(string value)
        {
            SpeechStatusText.Content = value;
            BackgroundWorker backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += new DoWorkEventHandler(DelayResetSpeechStatusText);
            backgroundWorker.RunWorkerAsync();
        }

        private void DelayResetSpeechStatusText(object sender, DoWorkEventArgs e)
        {
            Thread.Sleep(8000);
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                SpeechStatusText.Content = AppResources.listening;
            }
            );
        }

        private void ResetExecutingCommandStatus(object sender, DoWorkEventArgs e)
        {
            Thread.Sleep(2000);
            ExecutingCommand = false;
        }

        private void YesNext()
        {
        }

        private void NoNext()
        {
        }
    }
}